Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

[toc]

无连接通信(Verbindungslose Kommunikation)

无连接通信(Verbindungslose Kommunikation)的通道(Kanäle)可以按照带宽(Bandbreite)分成2种:

  1. 窄带通道(Schmalbandige Kanäle)
  2. 宽带通道(Breitbandige Kanäle)

窄带通道(Schmalbandige Kanäle)

窄带通道(Schmalbandige Kanäle)传输少量信息(wenige Bits),主要用于事件的通知(Melden von Ereignissen)。它需要同步机制和中断机制(Synchronisationskonzepte und Unterbrechungskonzepte )来确保通信的可靠性。

Linux里的例子:Signals

  • 进程可以互相发送信号(使用 kill() )

  • 进程可以显式捕获这些信号(使用 signal() ):

    • 可以通过注册一个信号处理函数(signal handler)来处理信号

    • 也忽略该信号(使用 SIG_IGN)

  • 如果一个进程没有捕获(abfangen)信号,那么操作系统会终止(beendet)该进程。
  • SIGKILL 和 SIGSTOP 是不能被捕获的,这些信号会强制终止或暂停进程,进程无法阻止或忽略它们

kill()函数的用法:

kill(pid, signal),其中pid是进程ID,signal是具体要发送的信号,可选的有:

信号名 作用说明
SIGHUP 终端挂起或控制进程终止,常用于重新加载配置
SIGINT 中断(通常来自 Ctrl+C)
SIGILL 非法指令,通常是程序错误导致
SIGABRT 异常终止(由 abort() 触发)
SIGKILL 强制终止,无法被捕获或忽略
SIGUSR1 用户自定义信号 1
SIGSEGV 段错误(Segmentation Fault)
SIGUSR2 用户自定义信号 2
SIGPIPE 管道破裂(写入没有读取端的 pipe)
SIGALRM 定时器信号(alarm() 到期触发)
SIGTERM 正常终止请求,默认的 kill 信号
SIGCHLD 子进程结束时通知父进程
SIGCONT 恢复被停止的进程
SIGSTOP 强制停止,无法被捕获或忽略
SIGTSTP 终端停止信号(Ctrl+Z)

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

// 信号处理函数:当接收到信号时执行
void sighandler(int sig) {
printf("Caught signal %d\n", sig);

// 重新注册信号处理器(旧版 signal API 需要这样做)
signal(SIGINT, sighandler); // Ctrl+C
signal(SIGALRM, sighandler); // alarm() 触发的定时器信号
}

int main(int argc, char *argv[], char *envp[]) {
char buffer[1024]; // 用于存储用户输入
int len;

// 注册信号处理函数
signal(SIGINT, sighandler); // 捕获 Ctrl+C
signal(SIGALRM, sighandler); // 捕获定时器 alarm 信号

// 设置一个定时器,5 秒后发送 SIGALRM 信号
alarm(5);

// 第一阶段:每秒打印一次计数,持续 10 秒
for (len = 0; len < 10; len++) {
printf("Counting %d...\n", len);
sleep(1); // 每秒暂停
}

// 第二次定时器设置,在 10 秒后发送另一个 SIGALRM
alarm(10);

// 第二阶段:进入一个循环,从标准输入读取用户输入
while (1) {
// 从标准输入读取内容(阻塞式)
len = read(0, buffer, sizeof(buffer) - 1);

if (len == -1) {
// 读取失败,打印错误并继续
perror("read() failed");
continue;
}

if (len == 0) {
// 读到 EOF(比如输入 Ctrl+D),退出程序
printf("Exiting\n");
exit(0);
}

buffer[len] = '\0'; // 添加字符串结尾符

// 如果用户输入的是 "exit",退出程序
if (!strncmp(buffer, "exit", 4)) {
exit(0);
}

// 把用户输入的内容原样输出回终端
write(1, buffer, strlen(buffer));
}

return 0;
}

输出示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
Counting 0...
Counting 1...
...
Counting 4...
Caught signal 14 <-- alarm(5) 到时触发 SIGALRM
Counting 5...
...
Counting 9...
hello, world <-- 用户输入
hello, world <-- 程序回显
Caught signal 14 <-- alarm(10) 又触发了 SIGALRM
^C Caught signal 2 <-- 用户按了 Ctrl+C,触发 SIGINT (signal 2)
exit <-- 用户输入 exit,触发退出

宽带通道(Breitbandige Kanäle)

宽带通道(Breitbandige Kanäle)用于传输大量数据,可以根据通信的方式进一步划分为:

  1. 隐式通信(Implizite Kommunikation)
  2. 显式通信(Explizite Kommunikation)

隐式通信(Implizite Kommunikation)

隐式通信(Implizite Kommunikation)通过共享资源实现的,比如说内存、寄存器、文件、环形缓冲区等。

优点:简单快速,因为不需要不需要在不同地址空间(Adressräumen)之间复制数据。

缺点:不一定一直都有共享区域可以用;可能会出现 busy-waiting,所以需要额外的同步机制。

(第三章的内容就是在讲这个)

而隐式通信(Implizite Kommunikation) 可以进一步划分为:

  1. 同步通信(Synchrone Kommunikation)

    发送方或接收方可能需要等待对方。

    比如说共享内存并且设置了同步机制。

  2. 异步通信(Asynchrone Kommunikation)

    发送和接收可以独立进行。

    比如说通过共享的文件进行kommunizieren。

显式通信(Explizite Kommunikation)

显式通信(Explizite Kommunikation)则是我们比较熟悉的:发送/接收信息。适用于地址空间(Adressräumen)分离的进程(比如两个互不相干的进程),不过是与操作系统的直接交互。

这种通信可以是本地的也可以是远程的。

一般信息由2部分组成:

  • 消息头(Nachrichtenkopf,header):包含管理信息,比如说发送者、接收者的标识、消息大小等。
  • 消息体(Nachrichtenkörper):有效载荷(payload),也就是真正的信息内容。

流程:

  1. 进程使用 send() 发送消息
  2. 操作系统的消息服务负责传递该消息
  3. 接收方进程使用 recv() 接收该消息

而显式通信(Explizite Kommunikation) 同样可以进一步划分为:

  1. 同步通信(Synchrone Kommunikation)

    发送方或接收方可能需要等待对方

  2. 异步通信(Asynchrone Kommunikation)

    发送和接收可以独立进行

这其中又有2种消息通信的模式(Muster):

  1. 消息通知(Meldung)

    是单向的(unidirectional),通常只是传递少量数据,比如说通知状态变化。

  2. 任务(Auftrag)

    是双向的(bidirectional),比如说查询某些数据,请求发送后收到包含数据的响应。

Asynchron的优点:

  • 在实时系统中非常有用,当发送进程不能被阻塞时;
  • 允许发送方和接收方并行处理任务;
  • 适合用于事件的通知/信号传递。

Asynchron的缺点:

  • 操作系统有管理负担(需要消息缓冲区来存储异步数据)
  • 错误处理更复杂:
    • 无法直接通知发送方是否成功;
    • 数据包可能丢失(当缓冲区满了,尤其是网络通信中);
    • 有时需要重传数据包。

在实际应用中,异步通信更常用,特别适用于不确定接收方是否在线、或者无法预测响应时间的情况。

可以使用线程来结合同步与异步通信(比如:主线程同步处理、子线程异步等待)。

Asynchrone Meldung

只发不等

image-20250405155011380

Synchrone Meldung

等待对方确认收到

流程:

  • 接收方在收到消息后会发送一个确认(Bestätigung)
  • 发送方在发送完消息后会等待接收确认(Empfangsbestätigung)

确认消息不包含实际数据,仅用于同步。

image-20250405155154111

另一种方法:Rendezvous-Verfahren

  • 在交换消息之前,发送方与接收方都要事先准备好进行发送和接收
  • 这样一来消息不需要缓冲

Asynchrone Auftrag

各发各的

任务(Auftrag)和结果(Resultat)是作为两个独立的消息发送的。

image-20250405155207289

Synchrone Auftrag

等待对方回复

image-20250405155909542

Streams

流(Stream)是对连接(Verbindung)的一种抽象。

消息在传输过程中被缓冲,所有消息被整合为逻辑上的字节流(byte stream)。

操作系统可以建立/关闭连接,或者是在流中进行读/写操作。

C++头文件中的

1
#include <iostream>

指的就是这个。

而管道(Pipes)正是流(Stream)的实现。

管道是一个单向的流(unidirektionaler Strom)。双向通信可以用两个管道来模拟。管道实现先进先出(FIFO) 的数据传输模型。

管道(Pipes)一般分为2种:

  1. (匿名)管道

    pipe() 函数会创建一个管道,它返回两个文件描述符,分别用于读和写。

    可以在 fork() 创建子进程时,把其中一端交给子进程,实现进程间通信,或者在不同的线程之间使用。

  2. 命名管道(Named Pipes)

    用于多个进程之间的通信,它们有自己的名字,在文件系统中可见。

代码示例:

1
2
3
4
5
6
7
8
9
int main() {
int p[2]; // p[0]: 读端, p[1]: 写端
pipe(p); // 创建一个匿名管道

sendData(p[1]); // 写数据到管道
receiveData(p[0]); // 从管道中读取数据

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
void sendData(int fd) {
const char *msg = "Hello, world"; // 要发送的消息
uint16_t len = strlen(msg); // 消息长度(不含 \0)
uint16_t nLen = htons(len); // 转换为网络字节序(大端)

// 先发送长度,确保接收端知道后面要读取多少字节
send(fd, &nLen, sizeof(nLen), 0);

// 再发送消息本体
send(fd, msg, len, 0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void receiveData(int fd) {
char msg[1024]; // 接收缓冲区
uint16_t nLen; // 网络字节序长度
uint16_t len; // 主机字节序长度

// 先接收长度信息(2字节)
recv(fd, &nLen, sizeof(nLen), 0);
len = ntohs(nLen); // 转换为主机字节序

// 接收实际消息内容(len 字节)
recv(fd, msg, len, 0);

msg[len] = '\0'; // 手动加上字符串结束符
printf("接收到 %u 字节:%s\n", len, msg);
}

例题

例题1

Für wehlche der folgenden IPC-Mechanismen wird in der Regel ein Filedescriptor verwendent?

  1. Sockets
  2. Shared Memory
  3. Anon. Pipes
  4. Named Pipes
  5. Signals

答案:1,3,4。